//		TODO commentaar (schrijven + checken)
public enum Temperature {
	
	FAHRENHEIT{
		public char getSymbol(){
			return 'F';
		}
		public double convertTo(double temperature, Temperature scale) {
			if(scale == CELCIUS)
				return convertFahrenheitToCelcius(temperature);
			if(scale == KELVIN)
				return convertFahrenheitToKelvin(temperature);
			return temperature;
		}
		
		public  boolean isValidTemperature(double temperature, Temperature scale){
			if (scale == CELCIUS){
				
				return ( (Temperature.MAX_VALUE  > Math.abs(temperature))
						&& ((Double.MIN_VALUE < Math.abs(temperature))
								||(Math.abs(temperature)==0)));
			}
			
			if (scale == FAHRENHEIT)
				return ( (Temperature.MAX_VALUE > Math.abs((temperature -32)/9*5))
						&& ((Double.MIN_VALUE < Math.abs(temperature))
								||(Math.abs(temperature)==0)));
			
			if (scale == KELVIN){
				boolean isValidCelcius = Temperature.CELCIUS.isValidTemperature(temperature, Temperature.KELVIN);
				double temperatureInCelcius = convertKelvinToCelcius(temperature);
				boolean isValidFahrenheit = Temperature.FAHRENHEIT.isValidTemperature(temperatureInCelcius, Temperature.CELCIUS);
				return (isValidCelcius && isValidFahrenheit);}
			return false;
			
		}
	}, CELCIUS{
		public char getSymbol(){
			return 'C';
		}
		public double convertTo(double temperature, Temperature scale) {
			if(scale == FAHRENHEIT)
				return convertCelciusToFahrenheit(temperature);
			if(scale == KELVIN)
				return convertCelciusToKelvin(temperature);
			return temperature;
		}
		
		public  boolean isValidTemperature(double temperature, Temperature scale){
			if (scale == KELVIN)
				return( (Temperature.MAX_VALUE > Math.abs(temperature - 273.15))
						&& ((Double.MIN_VALUE  < Math.abs(temperature - 273.15))
								||(Math.abs(temperature)==0)));
			
			if (scale == FAHRENHEIT)
				return ( (Temperature.MAX_VALUE > Math.abs((temperature -32)/9*5))
						&& ((Double.MIN_VALUE *9/5  < Math.abs(temperature -32 ))
								||(Math.abs(temperature)==0)));
			
			if (scale == CELCIUS)
				return ( Temperature.MAX_VALUE > Math.abs(temperature) 
						&& ((Double.MIN_VALUE < Math.abs(temperature))
								||(Math.abs(temperature)==0)));
			return false;
		}
	},
	KELVIN{
		public char getSymbol(){
			return 'K';
		}
		public double convertTo(double temperature, Temperature scale) {
			if(scale == FAHRENHEIT)
				return convertKelvinToFahrenheit(temperature);
			if(scale == CELCIUS)
				return convertKelvinToCelcius(temperature);
			return temperature;
		}
		public boolean isValidTemperature(double temperature, Temperature scale){
			if (scale == CELCIUS)
				return ((Temperature.MAX_VALUE  > Math.abs(temperature)) 
						&& ((Double.MIN_VALUE < Math.abs(temperature) )
								||(Math.abs(temperature)==0)));
			
			if (scale == KELVIN)
				return ((Temperature.MAX_VALUE > Math.abs(temperature- 273.15)) 
						&& ((Double.MIN_VALUE < temperature )
								||(Math.abs(temperature)==0)));
			
			if (scale == FAHRENHEIT){
				boolean isValidCelcius = Temperature.CELCIUS.isValidTemperature(temperature, Temperature.FAHRENHEIT);
				double temp = convertFahrenheitToCelcius(temperature);
				boolean isValidKelvin = Temperature.KELVIN.isValidTemperature(temp, Temperature.CELCIUS);
				return (isValidCelcius && isValidKelvin);}
			return false;
		}
	};
	// TODO MAX_VALUE private of niet?
	/**
	 * A constant containing a double of the highest temperature in celcius the class can work with. 
	 */
	private final static double MAX_VALUE = 10*Math.exp(20);
	public abstract char getSymbol();
	/**
	 * 
	 * @param 	temperature
	 * @param	scale
	 * 			The scale to which to convert. 
	 * @return
	 */
	public abstract double convertTo(double temperature, Temperature scale);
	/**
	 * 
	 * @param 	temperature
	 * @param 	scale
	 * 			The scale in which the temperature is expressed
	 * @return
	 */
	public abstract boolean isValidTemperature(double temperature, Temperature scale);
	
	/**
	 * This method converts the temperature from degrees Celcius to Kelvin.
	 * 
	 * @param  	temperature
	 * 		  	The temperature in degrees Celcius as a double to convert.	
	 * @return	returns the converted temperature as a double.
	 * 			| result == temperature + 273.15
	 * @throws 	IllegalArgumentException
	 * 			|	! isValidTemperature(temperature + 273.15)
	 */
	private static double convertCelciusToKelvin(double temperature) throws IllegalArgumentException{
		if (( !Temperature.KELVIN.isValidTemperature(temperature, Temperature.CELCIUS)))
			throw new IllegalArgumentException();
		
		return temperature + 273.15;
	}
	
	/**
	 * This method converts the temperature from Kelvin to degrees Celcius.
	 * 
	 * @param  	temperature
	 * 		  	The temperature in Kelvin as a double to convert.
	 * @return 	returns the converted temperature as a double.
	 * 			| result == temperature - 273.15
	 * @throws 	IllegalArgumentException
	 * 			|	! isValidTemperature(temperature)
	 */
	private static double convertKelvinToCelcius(double temperature){
		if (( !Temperature.CELCIUS.isValidTemperature(temperature, Temperature.KELVIN)))
			throw new IllegalArgumentException();
		return temperature - 273.15;
	}
	
	/**
	 * This method converts the temperature from degrees Fahrenheit to degrees Celcius
	 * 
	 * @param  	temperature
	 * 		  	The temperature in Fahrenheit as a double to convert.
	 * @return 	returns the converted temperature as a double.
	 * 			| result == (temperature - 32)*(5/9)
	 * @throws 	IllegalArgumentException
	 * 			|	! isValidTemperature((temperature - 32)*5/9)
	 */
	private static double convertFahrenheitToCelcius(double temperature ){
		if ( !Temperature.CELCIUS.isValidTemperature(temperature, FAHRENHEIT))
			throw new IllegalArgumentException();
		return (temperature - 32)*5/9; 
	}
	
	/**
	 * This method converts the temperature from degrees Celcius to degrees Fahrenheit.
	 * 
	 * @param  	temperature
	 * 		  	The temperature in degrees Celcius as a double to convert.
	 * @return 	returns the converted temperature as a double.
	 * 			| result == temperature*9/5 + 32
	 * @throws 	IllegalArgumentException
	 * 			|	! isValidTemperature((temperature*9)/5 + 32)
	 */
	private  static double convertCelciusToFahrenheit(double temperature){
		if ( !Temperature.FAHRENHEIT.isValidTemperature(temperature, Temperature.CELCIUS))
			throw new IllegalArgumentException();
		return (temperature*9)/5 + 32;
	}
	
	/**
	 * This method converts the temperature from degrees Fahrenheit to Kelvin.
	 * 
	 * @param  	temperature
	 * 		  	The temperature in Fahrenheit as a double to convert.
	 * @return 	returns the converted temperature as a double.
	 * 			| result == 
	 * 			|	convertCelciusToKelvin(convertFahrenheitToCelcius(temperature))
	 * @effect	TODO
	 */
	private static double convertFahrenheitToKelvin(double temperature){
		return convertCelciusToKelvin(convertFahrenheitToCelcius(temperature));
	}
	
	/**
	 * This method converts the temperature from Kelvin to degrees Fahrenheit.
	 * 
	 * @param  	temperature
	 * 		  	The temperature in Kelvin as a double to convert.
	 * @return 	returns the converted temperature as a double.
	 * 			| result ==
	 * 			|	convertCelciusToFahrenheit(convertKelvinToCelcius( temperature))
	 * @effect	TODO
	 */
	private static double convertKelvinToFahrenheit(double temperature){
		return convertCelciusToFahrenheit(convertKelvinToCelcius(temperature));
	}
	
//	public static boolean isValidTemperature(double temperature){
//		return ( (temperature <= Double.MAX_VALUE) && (temperature >= Double.MIN_VALUE)) ;
//	}
}
